import {
    ArcRotateCamera,
    BackgroundMaterial,
    Color3,
    Color4,
    CubeTexture,
    Effect,
    Engine,
    HemisphericLight,
    Matrix,
    Mesh,
    MeshBuilder,
    MirrorTexture,
    Plane,
    Scene,
    ShaderMaterial,
    Size,
    StandardMaterial,
    Texture,
    Vector3,
} from "@babylonjs/core";
import { getDefaultMatrix } from '../component/MathLib'
import { act } from "react-dom/test-utils";

//天空盒
export default class SkyBox {
    public engine: Engine;
    public scene: Scene;
    public canvas: HTMLCanvasElement;

    private updateAction: Map<number, (time: number) => {}> = new Map();
    private updateActionId: number = 0;

    public static skyBox: SkyBox;

    public constructor(canvas: HTMLCanvasElement) {
        this.canvas = canvas;
        this.engine = new Engine(canvas, true);
        this.scene = this.createScene();

        this.init();

        SkyBox.skyBox = this;
    }

    private init() {
        this.update(0);
    }

    private createScene() {
        const { engine, canvas } = this;
        let scene = new Scene(engine);
        scene.clearColor = new Color4(0, 0, 0, 1);

        const camera = new ArcRotateCamera("Camera", Math.PI / 1.5, Math.PI / 3, 10, new Vector3(0, 0, 0), scene);
        camera.attachControl(canvas, true);




        const imageGround = MeshBuilder.CreateGround('ground', { width: 5, height: 3 });
        const mat = new ShaderMaterial(
            'shader01',
            scene,
            '../shader/shader01',
            {
                attributes: ['position', 'normal', 'uv'],
                uniforms: ['worldViewProjection', 'u_Set'],
                samplers: ['u_Image', 'u_Noise'],
            }
        );
        const imageTetxure = new Texture('./image/image01.png');
        mat.setTexture('u_Image', imageTetxure);
        const noiseTetxure = new Texture('./image/noise01.png');
        mat.setTexture('u_Noise', noiseTetxure);

        imageGround.material = mat;
        imageGround.rotation.set(-Math.PI / 2, Math.PI, 0);
        imageGround.position.y = 1.5;

        this.addAction((time: number) => {
            const set = (Math.sin(time / 1000) + 1) / 2 * 1.2;

            mat.setFloat('u_Set', set);
            // if (set >= 1) {
            //     imageGround.isVisible = false;
            // } else {
            //     imageGround.isVisible = true;
            // }
            return '';
        });


        const ground = MeshBuilder.CreateGround('ground', { width: 10, height: 10 });
        const mirror = new MirrorTexture('mirror', 1024);
        mirror.renderList = [imageGround];
        mirror.mirrorPlane = new Plane(0, -1, 0, 0);
        const backMat = new BackgroundMaterial('backMat');
        backMat.reflectionTexture = mirror;
        backMat.useRGBColor = false;
        backMat.primaryColor = new Color3(1, 1, 1);
        backMat.reflectionFresnel = true;
        backMat.reflectionStandardFresnelWeight = 0.9;
        ground.material = backMat;

        return scene;
    }

    private update(time: number) {
        const { updateAction, scene } = this;
        updateAction.forEach((action, key) => {
            action(time);
        });
        scene.render();
        requestAnimationFrame((time) => {
            this.update(time);
        });
    }

    public setUpdateAction(action: (time: number) => {}, id: number = -1) {
        const { updateAction } = this;
        let curId = id;
        if (id == -1) {
            curId = this.updateActionId++;
        } else if (id >= this.updateActionId) {
            curId = this.updateActionId++;
        }
        updateAction.set(curId, action);
    }

    public addAction(action: (time: number) => {}) {
        this.setUpdateAction(action, -1);
    }
}
